package com.gitee.wsl.mathematics.matrix.mat4

import com.gitee.wsl.ext.array.DoubleArray
import com.gitee.wsl.io.dataproxy.DataProxy
import com.gitee.wsl.io.dataproxy.asProxy
import com.gitee.wsl.mathematics.matrix.M
import com.gitee.wsl.mathematics.matrix.MatCopyInitializer
import com.gitee.wsl.mathematics.matrix.MatInitializer
import com.gitee.wsl.mathematics.matrix.N
import com.gitee.wsl.mathematics.matrix.mat2.MutableMat2
import com.gitee.wsl.mathematics.matrix.mat2.MutableMatrix2
import com.gitee.wsl.mathematics.matrix.mat3.MutableMat3
import com.gitee.wsl.mathematics.matrix.mat3.MutableMatrix3
import com.gitee.wsl.mathematics.vector.vec3.MutableVec3
import com.gitee.wsl.mathematics.vector.vec4.MutableVec4
import com.gitee.wsl.mathematics.vector.vec4.MutableVector4
import com.gitee.wsl.mathematics.vector.vec4.Vec4

open class MutableMat4(m00: Double=0.0, m01: Double=0.0, m02: Double=0.0, m03: Double=0.0,
                       m10: Double=0.0, m11: Double=0.0, m12: Double=0.0, m13: Double=0.0,
                       m20: Double=0.0, m21: Double=0.0, m22: Double=0.0, m23: Double=0.0,
                       m30: Double=0.0, m31: Double=0.0, m32: Double=0.0, m33: Double=0.0,
                       override val proxy: DataProxy<Double> =
                      DoubleArray(
                          m00, m01, m02, m03,
                          m10, m11, m12, m13,
                          m20, m21, m22, m23,
                          m30, m31, m32, m33
                      ).asProxy())
    :Mat4(proxy = proxy),MutableMatrix4D<Mat4, Vec4> {
    constructor(other: Matrix4D<*, *>):this(
        other.m00, other.m01, other.m02, other.m03,
        other.m10, other.m11, other.m12, other.m13,
        other.m20, other.m21, other.m22, other.m23,
        other.m30, other.m31, other.m32, other.m33
    )
    constructor(initializer: MatInitializer<Double>):this(
        initializer(0,0),initializer(0,1),initializer(0,2),initializer(0,3),
        initializer(1,0),initializer(1,1),initializer(1,2),initializer(1,3),
        initializer(2,0),initializer(2,1),initializer(2,2),initializer(2,3),
        initializer(3,0),initializer(3,1),initializer(3,2),initializer(3,3)
    )

    override val self
        get() = this

    override val m by lazy{listOf(M[0], M[1],M[2], M[3])}

    override val n by lazy {listOf(N[0], N[1],N[2], N[3])}

    //override fun createVec(indexRage:IntRange) = createVec(indexRage.toList())

    override fun createVec(indexes: List<Int>) = MutableVec4(proxy = proxy.asProxy(indexes))

    override fun createVec3(x: Double, y: Double, z: Double) = MutableVec3(x, y, z)

    override fun createVec4(block: (MutableVector4<Double, *>) -> Unit): MutableVec4 {
        val ret = MutableVec4()
        block(ret)
        return ret
    }

    override fun createMat2(block: (MutableMatrix2<Double, *, *>) -> Unit): MutableMat2 {
        val ret = MutableMat2()
        block(ret)
        return ret
    }

    override fun createMat3(block: (MutableMatrix3<Double, *, *>) -> Unit): MutableMat3 {
        val ret = MutableMat3()
        block(ret)
        return ret
    }

    override fun create(
        m00: Double, m01: Double, m02: Double, m03: Double,
        m10: Double, m11: Double, m12: Double, m13: Double,
        m20: Double, m21: Double, m22: Double, m23: Double,
        m30: Double, m31: Double, m32: Double, m33: Double,
    ) = MutableMat4(
        m00, m01, m02, m03,
        m10, m11, m12, m13,
        m20, m21, m22, m23,
        m30, m31, m32, m33
    )

    override fun toMutable() = this


    override operator fun M.get(row: Int) = createVec(rowIndexes(row))

    override operator fun N.get(col: Int) = createVec(colIndexes(col))

    override fun copy(block: MatCopyInitializer<Double>) = MutableMat4{ i, j->
        this[i,j].block(i,j)
    }

    companion object{

        val IDENTITY  = identity()

        fun identity()= MutableMat4(
            1.0, 0.0, 0.0, 0.0,
            0.0, 1.0, 0.0, 0.0,
            0.0, 0.0, 1.0, 0.0,
            0.0, 0.0, 0.0, 1.0
        )
    }
}